package com.gali.lovefinder.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.Hutool;
import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.QueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gali.lovefinder.common.ErrorCode;
import com.gali.lovefinder.constant.LoginTypeEnum;
import com.gali.lovefinder.constant.MessageTypeEnum;
import com.gali.lovefinder.constant.RedisConstant;
import com.gali.lovefinder.constant.UserConstant;
import com.gali.lovefinder.exception.BusinessException;
import com.gali.lovefinder.factory.message.MessageHandler;
import com.gali.lovefinder.factory.message.MessageHandlerFactory;
import com.gali.lovefinder.mapper.UserMapper;
import com.gali.lovefinder.model.bo.user.UserRegisterBO;
import com.gali.lovefinder.model.entity.User;
import com.gali.lovefinder.service.UserService;
import com.gali.lovefinder.utils.AssertUtil;
import com.gali.lovefinder.utils.GsonUtil;
import com.gali.lovefinder.utils.UserInfoUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import javax.annotation.Resource;
import java.util.Objects;

/**
 * @author gali
 * @description 针对表【user(用户)】的数据库操作Service实现
 * @createDate 2023-07-03 23:05:04
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
        implements UserService {
    @Resource
    private UserMapper userMapper;

    private  String regex = "\\w+@\\w+(\\.\\w{2,3})*\\.\\w{2,3}";
    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 盐值
     */
    private static final String SALT = "gali_mikey_loveFinder";

    @Override
    public void register(UserRegisterBO userRegisterBO) {
        //1.判断邮箱格式是否正确
        if(!userRegisterBO.getUserCount().matches(regex)){
            log.error("Failed to register,user info:{}", GsonUtil.toJson(userRegisterBO.getUserCount()));
            throw new BusinessException(ErrorCode.EMAIL_FORMAT_ERROR, "Email format error");
        }
        try {
            //2.判断用户是否注册
            Long userCount = this.query().eq("userAccount", userRegisterBO.getUserCount()).last("limit 1").count();
            if (userCount > 0) {
                throw new BusinessException(ErrorCode.USER_ALREADY_EXISTS, "User already exists");
            }

            //3.判断redis中是否存在验证码
            String redisKey = String.format(LoginTypeEnum.getLoginTypeEnum(userRegisterBO.getLoginType()).getRedisKey(),
                    userRegisterBO.getUserCount());
            Boolean isExits = redisTemplate.hasKey(redisKey);
            if (Boolean.FALSE.equals(isExits)) {
                log.error("user code error: {}", GsonUtil.toJson(userRegisterBO));
                throw new BusinessException(ErrorCode.MESSAGE_CODE_NOT_EXISTS, "user code error");
            }

            String messageCode = GsonUtil.fromJsonObject((String) redisTemplate.opsForValue().get(redisKey), String.class);

            if (Objects.nonNull(messageCode) && !messageCode.equals(userRegisterBO.getMessageCode())) {
                log.error("user code error: {}", GsonUtil.toJson(userRegisterBO.getMessageCode()));
                throw new BusinessException(ErrorCode.MESSAGE_CODE_ERROR, "user code error");
            }


            //4.密码加密（需要加盐值，安全性更高）
            User user = new User();
            user.setUserAccount(userRegisterBO.getUserCount());
            user.setUserName("loveFinder" + RandomUtil.randomString(6));
            user.setUserAvatar(UserConstant.DEFAULT_AVATAR);
            user.setGender(UserConstant.DEFAULT_GENDER);
            user.setUserRole(UserConstant.DEFAULT_ROLE);
            user.setUserPassword(DigestUtils.md5DigestAsHex((SALT + userRegisterBO.getPassword()).getBytes()));

            this.save(user);

            redisTemplate.delete(redisKey);
        } catch (Exception e) {
            log.error("Failed to register,user info:{}", GsonUtil.toJson(userRegisterBO), e);
            throw new BusinessException(ErrorCode.SAVE_ERROR);
        }
    }

    @Override
    public void getMessageCode(String userCount, String messageType) {
        MessageHandler handler = MessageHandlerFactory.getHandler(MessageTypeEnum.getMessageTypeEnum(messageType));
        handler.sendMessage(userCount);
    }

    @Override
    public String login(String userCount, String password) {
        //1.判断邮箱格式是否正确
        if(!userCount.matches(regex)){
            log.error("Failed to login,user info:{}", GsonUtil.toJson(userCount));
            throw new BusinessException(ErrorCode.EMAIL_FORMAT_ERROR, "Email format error");
        }
        //2.判断用户是否存在
        Long count = this.query().eq("userAccount", userCount).count();
        if (count == 0) {
            log.error("Failed to login,user info:{}", GsonUtil.toJson(userCount));
            throw new BusinessException(ErrorCode.USER_ALREADY_EXISTS, "User already exists");
        }

        //3.判断密码是否正确
        String md5Password = DigestUtils.md5DigestAsHex((SALT + password).getBytes());
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq("userAccount", userCount);
        userQueryWrapper.eq("userPassword", md5Password);

        User user = this.getOne(userQueryWrapper);
        if (Objects.isNull(user)) {
            log.error("Failed to login,user info:{}", GsonUtil.toJson(userCount));
            throw new BusinessException(ErrorCode.PASSWORD_OR_USER_COUNT_ERROR, "userCount or Password error");
        }

        //3.用户脱敏
        User safetyUser = getSafetyUser(user);

        //4. 记录用户的登录态
        StpUtil.login(safetyUser.getId());
        UserInfoUtil.setUserId(safetyUser.getId());
        return StpUtil.getTokenInfo().tokenValue;
    }

    @Override
    public void updatePwd(String newPwd, String oldPwd,Long id) {
        String pwd=userMapper.selectById(id).getUserPassword();
        if (pwd.equals(oldPwd)&&!newPwd.equals(pwd)){
            User user = new User();
            user.setId(id);
            user.setUserPassword(DigestUtils.md5DigestAsHex((SALT + newPwd).getBytes()));
            userMapper.updateById(user);
        }
        else {
            throw new BusinessException(ErrorCode.PASSWORD_OR_USER_COUNT_ERROR, "userCount or Password error");
        }
    }

    private User getSafetyUser(User user) {
        if (user == null) {
            return null;
        }
        User safeUser = new User();
        safeUser.setId(user.getId());
        safeUser.setUserName(user.getUserName());
        //脱敏
        safeUser.setUserAccount(StrUtil.hide(user.getUserAccount(), 3, 3));
        safeUser.setUserAvatar(user.getUserAvatar());
        safeUser.setGender(user.getGender());
        safeUser.setUserRole(user.getUserRole());
        safeUser.setUserPassword(DesensitizedUtil.password(user.getUserPassword()));
        safeUser.setCreateTime(user.getCreateTime());
        safeUser.setUpdateTime(user.getUpdateTime());
        safeUser.setIsDelete(user.getIsDelete());
        return safeUser;
    }
}




